package pda;

import java.util.Objects;

/**
 * @author haoly
 * @title PDARule
 * @date 2025/4/21 10:14
 * @description TODO
 */
public class PDARule<T> {
    private final T state;

    private final Character character;

    private final T nextState;

    private final Character popCharacter;

    private final String pushCharacters;

    public PDARule(T state, Character character, T nextState, Character popCharacter, String pushCharacters) {
        this.state = state;
        this.character = character;
        this.nextState = nextState;
        this.popCharacter = popCharacter;
        this.pushCharacters = pushCharacters;
    }

    public Boolean appliesTo(PDAConfiguration <T> configuration, Character character){

        return Objects.equals(this.state, configuration.getState()) && Objects.equals(this.character, character)
                && Objects.equals(this.popCharacter, configuration.getStack().top());
    }

    public PDAConfiguration<T> follow(PDAConfiguration<T> configuration){
        Stack<Character> nextStack = nextStack(configuration);

        return new PDAConfiguration<>(nextState, nextStack);

    }

    private Stack<Character> nextStack(PDAConfiguration<T> configuration) {
        Stack<Character> oldStack = configuration.getStack();
        Stack<Character> freshStack = oldStack.copy();
        freshStack.pop();
        for (int i = pushCharacters.length() - 1; i >= 0; i--) {
            Character character = pushCharacters.charAt(i);
            freshStack.push(character);

        }
        return freshStack;
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("#struct PDARule ");
        sb.append("state=").append(state).append(",");
        sb.append("character=").append(character).append(",");
        sb.append("nextState=").append(nextState).append(",");
        sb.append("popCharacter=").append(popCharacter).append(",");
        sb.append("pushCharacters=").append(pushCharacters);
        sb.append(">");
        return sb.toString();
    }
}
